package com.qfedu.edu.seckill.filter;

import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson2.JSON;
import com.qfedu.edu.seckill.exception.BusinessException;
import com.qfedu.edu.seckill.manager.RedisManager;
import com.qfedu.edu.seckill.result.R;
import com.qfedu.edu.seckill.result.ResponseCode;
import com.qfedu.edu.seckill.utils.HttpResponseUtils;
import org.qfedu.edu.seckill.service.IJwtService;
import org.qfedu.edu.seckill.service.ITokenService;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * 这个过滤器是咋们的认证的过滤器
 */
public class AuthenticationFilter extends BasicAuthenticationFilter {
    private AuthenticationManager authenticationManager;
    private ITokenService tokenService;
    private RedisManager redisManager;

    private IJwtService jwtService;

    public AuthenticationFilter(AuthenticationManager authenticationManager,
                                ITokenService tokenService,
                                RedisManager redisManager,
                                IJwtService jwtService) {
        super(authenticationManager);
        this.authenticationManager=authenticationManager;
        this.tokenService=tokenService;
        this.redisManager=redisManager;
        this.jwtService=jwtService;
    }


    /**
     * 这个方法中就要编写认证的这个逻辑
     * @param request
     * @param response
     * @param chain
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        /**
         * 实现的思路：
         *   1、找到这个token
         *   2、校验这个token的合法性
         *   3、还要将权限信息和角色信息取出来放到上下文中 方便去进行 鉴权
         */
        //取出token
        String token = request.getHeader("token");
        //在这里还需要校验这个请求是不是来自于 网关
        String gatewayTag = request.getHeader("gatewayTag");
        if(StringUtils.isEmpty(gatewayTag)){
           //说明请求是非法请求
            HttpResponseUtils.sendResponse(response,R.error(ResponseCode.AUTHENTICATION_EXCEPTION));
            return;
        }
        //校验token的合法性
        if(verifyToken(token,request,response)){
            //找到用户信息
            String userId = this.jwtService.getUserId(token);
            String username = this.jwtService.getUsername(token);

            //执行到这里 说明这个token是合法的
            //取出这个角色和权限信息
            String jsonStr=redisManager.getString(token);
            //将上面的json格式弄成List<String>
            List<String> roleAndPerms = JSON.parseArray(jsonStr, String.class);
            //申明一个需要的List集合
            List<GrantedAuthority> grantedAuthorities=new ArrayList<>();
            //接下来将角色和权限弄成 需要的格式
            if(null!=roleAndPerms||roleAndPerms.size()!=0){
                //说明有信息
                for (int i = 0; i <roleAndPerms.size() ; i++) {
                    grantedAuthorities.add(new SimpleGrantedAuthority(roleAndPerms.get(i)));
                }
            }
            //接下来封装信息
            UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(userId, username, grantedAuthorities);
            //接下来就需要将这个信息 直接放到 上下文中去
            SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
            chain.doFilter(request,response);
        }
    }

    /**
     * 校验token的合法性(需要修改)
     * @param token
     */
    private boolean verifyToken(String token,HttpServletRequest req,HttpServletResponse resp) {
        if(null==token||StringUtils.isEmpty(token)){
            HttpResponseUtils.sendResponse(resp, R.error(ResponseCode.AUTHENTICATION_EXCEPTION));
            //先要响应数据 然后 停止运行
            return false;
        }
        //下面就可以开始进行校验了
        boolean b = tokenService.verifyToken(token);
        if(!b){
            //先要响应数据 然后 停止运行
            HttpResponseUtils.sendResponse(resp, R.error(ResponseCode.AUTHENTICATION_EXCEPTION));
            //先要响应数据 然后 停止运行
            return false;
        }else {
            return true;
        }
    }
}
